#include "stdafx.h"
#include "xKernel/IxFileManager.h"
#include "rapidxml/rapidxml.hpp"
#include "DescManager.h"

CxDescManager::CxDescManager()
{}

CxDescManager::~CxDescManager()
{}

HRESULT CxDescManager::GetDescription(BSTR bsFile, IxPairVec** ppDesc)
{
    if (!ppDesc)
    {
        return E_POINTER;
    }

    *ppDesc = NULL;

    CComPtr<IxFileManager> spFileMgr;
    ::xCommon::GetService(__uuidof(IxFileManager), (void**)&spFileMgr);
    if (spFileMgr)
    {
        CString strFile = bsFile;

        INT nPos = strFile.ReverseFind('|');

        CString strName = strFile.Right(strFile.GetLength() - nPos - 1);
        strFile = strFile.Left(nPos);

        CComPtr<IxBuffer> spBuffer;
        spFileMgr->GetBuffer(CComBSTR(strFile), &spBuffer);
        if (spBuffer)
        {
            LPBYTE pbyBuffer = NULL;
            spBuffer->GetBuffer(&pbyBuffer);
            if (pbyBuffer)
            {
                xml_document<> doc;                             // character type defaults to char

                try
                {
                    doc.parse<0>((char*)pbyBuffer);             // 0 means default parse flags
                }
                catch (rapidxml::parse_error& e)
                {
                    UNREFERENCED_PARAMETER(e);
                    ATLASSERT(!L"Incorrect xml formate!!!");
                    return E_FAIL;
                }

                CStringA strName_utf8 = (::xBase::WideCharToMultiByte(strName, CP_UTF8)).c_str();

                xml_node<>* node = doc.first_node();

                while (node)
                {
                    xml_attribute<>* pAttri = node->first_attribute();
                    if (pAttri)
                    {
                        if (strName_utf8 == pAttri->value())
                        {
                            ::xCommon::CreateObjectByIID(__uuidof(IxPairVec), (void**)ppDesc);
                            if (*ppDesc)
                            {
                                _parse(node, *ppDesc);
                            }
                            else
                            {
                                ATLASSERT(!L"Create IxPairVec Failure!!!");
                            }
                            break;
                        }
                    }

                    node = node->next_sibling();
                }
            }
        }
    }

    return E_FAIL;
}

void CxDescManager::_parse(const xml_node<>* const node, IxPairVec* pVec)
{
    if (!node || !pVec)
    {
        return;
    }

    CString strName = (::xBase::MultiByteToWideChar(node->name(), CP_UTF8)).c_str();

    pVec->AddStr(CComBSTR(L"interface"), CComBSTR(strName));

    CComPtr<IxPairVec> spAttributes;
    ::xCommon::CreateObjectByIID(__uuidof(IxPairVec), (void**)&spAttributes);

    if (spAttributes)
    {
        pVec->AddInterface(CComBSTR(L"attribute"), spAttributes);

        xml_attribute<>* pAttri = node->first_attribute();

        // Ignore the Name Attribute
        if (pAttri && 0 == strcmp(pAttri->name(), "Name"))
        {
            pAttri = pAttri->next_attribute();
        }

        CString strAttriName;
        CString strAttriValue;

        while (pAttri)
        {
            strAttriName = (::xBase::MultiByteToWideChar(pAttri->name(), CP_UTF8)).c_str();
            strAttriValue = (::xBase::MultiByteToWideChar(pAttri->value(), CP_UTF8)).c_str();

            spAttributes->AddStr(CComBSTR(strAttriName), CComBSTR(strAttriValue));

            pAttri = pAttri->next_attribute();
        }

        const xml_node<>* node_child = node->first_node();
        if (node_child && 0 == strcmp(node_child->name(), "Attribute"))
        {
            _parse_attribute(node_child, spAttributes);
            node_child = node_child->next_sibling();
        }

        if (node_child)
        {
            CComPtr<IxPairVec> spChildren;
            ::xCommon::CreateObjectByIID(__uuidof(IxPairVec), (void**)&spChildren);

            if (spChildren)
            {
                pVec->AddInterface(CComBSTR(L"children"), spChildren);
                _parse_children(node_child, spChildren);
            }
            else
            {
                ATLASSERT(!L"Create IxPairVec Failure!!!");
            }
        }
    }
}


void CxDescManager::_parse_attribute(const xml_node<>* const node, IxPairVec* pVec)
{
    if (!node || !pVec)
    {
        return;
    }

    xml_node<>* node_prop = node->first_node();

    CString strAttriName;
    CString strAttriValue;

    while (node_prop)
    {
        strAttriName = (::xBase::MultiByteToWideChar(node_prop->name(), CP_UTF8)).c_str();

        xml_attribute<>* pAttri_node_prop = node_prop->first_attribute();

        if (pAttri_node_prop && 0 == strcmp(pAttri_node_prop->name(), "Value"))
        {
            strAttriValue = (::xBase::MultiByteToWideChar(pAttri_node_prop->value(), CP_UTF8)).c_str();
            pVec->AddStr(CComBSTR(strAttriName), CComBSTR(strAttriValue));
        }
        else if (node_prop->first_node())
        {
            CComPtr<IxPairVec> spAttribute;
            ::xCommon::CreateObjectByIID(__uuidof(IxPairVec), (void**)&spAttribute);
            if (spAttribute)
            {
                pVec->AddInterface(CComBSTR(strAttriName), spAttribute);
                _parse(node_prop->first_node(), spAttribute);
            }
            else
            {
                ATLASSERT(!L"Create IxPairVec Failure!!!");
            }
        }
        else
        {
            ATLASSERT(!L"Wrong Attribute Format!!!");
        }

        node_prop = node_prop->next_sibling();
    }
}

void CxDescManager::_parse_children(const xml_node<>* const node, IxPairVec* pVec)
{
    if (!node || !pVec)
    {
        return;
    }

    const xml_node<>* child_node = node;

    CString strAttriName;

    CString strCount;
    INT nCount = 0;

    while (child_node)
    {
        CComPtr<IxPairVec> spVec;
        ::xCommon::CreateObjectByIID(__uuidof(IxPairVec), (void**)&spVec);
        if (spVec)
        {
            strCount.Format(_T("%d"), ++nCount);
            pVec->AddInterface(CComBSTR(strCount), spVec);
            _parse(child_node, spVec);
        }
        else
        {
            ATLASSERT(!L"Create IxPairVec Failure!!!");
        }

        child_node = child_node->next_sibling();
    }
}
